package med;

import java.io.BufferedReader;
import java.io.FileReader;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

import libsvm.svm;
import libsvm.svm_model;
import libsvm.svm_node;
import libsvm.svm_parameter;
import libsvm.svm_problem;
import med.config.Config;
import med.utils.Reader;

public class SVMModule {

	private svm_parameter mSvmParameter;
	private svm_model mSvmModel;
	private double minProbability = 40;
	public static double mParam = 4;
	
	public SVMModule()
	{
		mSvmParameter = new svm_parameter();
		mSvmParameter.svm_type = svm_parameter.C_SVC;
		mSvmParameter.C = 0.5;
		mSvmParameter.nu = 0.4;
		mSvmParameter.degree = 2;
		mSvmParameter.kernel_type = svm_parameter.RBF;
		mSvmParameter.gamma = 0.5;
		mSvmParameter.coef0 = 0;
		mSvmParameter.eps = 0.001 ;
		mSvmParameter.cache_size = 128;
		mSvmParameter.shrinking = 0;
		mSvmParameter.probability =1;
	}
	
	public SVMModule(String configFile)
	{
		this();
		BufferedReader rdr;
		StringBuilder sb = new StringBuilder();

		try {
			rdr = new BufferedReader(new FileReader(configFile));
			String line;
			while ((line = rdr.readLine()) != null) {
				sb.append(line + ' ');
			}
		} catch (Exception e) {
			throw new RuntimeException(e);
		}

		List<String> result = new LinkedList<String>();
		
		
		for (String token : sb.toString().split("\\s+")) {
				result.add(token);
			}
		
		Iterator<String> it = result.iterator();
				
		while( it.hasNext() )
		{
		
		String token = it.next();
		String value = null;
		if(token.contains("svm_type"))
		{
			value = it.next();
			mSvmParameter.svm_type = Integer.parseInt(value);
		}
		
		if(token.contains("C"))
		{
			value = it.next();
			mSvmParameter.C = Double.parseDouble(value);
		}
		if(token.contains("nu"))
		{
			value = it.next();
			mSvmParameter.nu = Double.parseDouble(value);
		}
		if(token.contains("degree"))
		{
			value = it.next();
			mSvmParameter.degree = Integer.parseInt(value);
		}
		if(token.contains("kernel_type"))
		{
			value = it.next();
			mSvmParameter.kernel_type = Integer.parseInt(value);
		}
		if(token.contains("gamma"))
		{
			value = it.next();
			mSvmParameter.gamma = Double.parseDouble(value);
		}
		if(token.contains("coef0"))
		{
			value = it.next();
			mSvmParameter.coef0 = Double.parseDouble(value);
		}
		if(token.contains("eps"))
		{
			value = it.next();
			mSvmParameter.eps = Double.parseDouble(value);
		}
		if(token.contains("cache_size"))
		{
			value = it.next();
			mSvmParameter.cache_size = Double.parseDouble(value);
		}
		if(token.contains("shrinking"))
		{
			value = it.next();
			mSvmParameter.shrinking = Integer.parseInt(value);
		}
		if(token.contains("minProb"))
		{
			value = it.next();
			minProbability = Double.parseDouble(value)/100;
		}
		if(token.contains("mParam"))
		{
			value = it.next();
			mParam = Double.parseDouble(value);
		}
		

		}
	}
	
	public void trainSVM(List<Element> elements)
	{
		int i = 0;
		svm_problem svmProblem = new svm_problem();
		svmProblem.y = new double[elements.size()];
		svmProblem.x = new svm_node[elements.size()][];
		svmProblem.l = elements.size();
		for (Element elem : elements) 
		{
			svmProblem.y[i] = elem.getType().ordinal();
			svmProblem.x[i] = elem.getSvmNode();	
			++i;
		}
		System.out.println("svm_check_parameter:	");
		
		System.out.println(svm.svm_check_parameter(svmProblem, mSvmParameter));
		
		mSvmModel = svm.svm_train(svmProblem, mSvmParameter);
	}
	
	public Element classification(Vector vector) {
		double[] ret = new double[mSvmModel.nr_class ];
		int elemId;
		svm_node[] svmNode = vector.getSvmNode();
		Type elemClass;
		Element element = null;
		elemId = (int)Math.round(svm.svm_predict_probability(mSvmModel,svmNode,ret));
		if (elemId <= 0)
			return null;
		boolean foundClass = false;
		for(int i = 0; i < mSvmModel.nr_class;i++)
		{
			if(ret[i] >= minProbability) 
			{
				foundClass = true;
				break;
			}
	}
		
		if(!foundClass) return null;
		
		elemClass = Type.values()[elemId];

		switch (elemClass) {
		case AcceptanceDate:
			element = new AcceptanceDate(vector);
			break;
		case CameraReadyDate:
			element = new CameraReadyDate(vector);
			break;
		case Committee:
			element = new Committee(vector);
			break;
		case ConferenceDate:
			element = new ConferenceDate(vector);
			break;
		case ConfernceName:
			element = new ConfernceName(vector);
			break;
		case ConferncePlace:
			element = new ConferencePlace(vector);
			break;
		case NameAbbrevation:
			element = new NameAbbreviation(vector);
			break;
		case PaperSubmitionAbstract:
			element = new PaperSubmissionAbstract(vector);
			break;
		case PaperSubmitionDate:
			 element = new PaperSubmissionDate(vector);
			break;
		case RegistrationDate:
			element = new RegistrationDate(vector);
			break;
		}
		return element;
	}

	public boolean isTrained() {
		return mSvmModel != null;
	}

}
